﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Happy.Domain.CommonModel.TreeLike
{
    /// <summary>
    /// 节点移动服务。
    /// </summary>
    public class MoveNodeService<TNodePathRepairer> : DomainService
        where TNodePathRepairer : INodePathRepairer
    {
        /// <summary>
        /// 移动到指定的父节点。
        /// </summary>
        public void MoveNodeTo<TNode, TId>(TNode node, TId? parentId)
            where TNode : TreeNode<TId>
            where TId : struct
        {
            if (node.ParentId.Equals(parentId))
            {
                return;
            }

            if (parentId == null)
            {
                this.MoveNodeToRoot<TNode, TId>(node);
            }
            else
            {
                var parent = this.LoadAggregate<TNode, TId>(parentId);
                this.MoveNodeTo<TNode, TId>(node, parent);
            }
        }

        /// <summary>
        /// 移动到指定的父节点。
        /// </summary>
        public void MoveNodeTo<TNode, TId>(TNode node, TNode parent)
            where TNode : TreeNode<TId>
            where TId : struct
        {
            if (node.ParentId.Equals(parent.Id))
            {
                return;
            }

            var oldPath = node.NodePath;
            node.MoveTo(parent);
            var newPath = node.NodePath;

            this.Service<TNodePathRepairer>()
                .UpdateDescendantsNodePath<TNode>(oldPath, newPath);
        }

        /// <summary>
        /// 移动到根节点。
        /// </summary>
        public void MoveNodeToRoot<TNode, TId>(TNode node)
            where TNode : TreeNode<TId>
            where TId : struct
        {
            if (node.ParentId == null)
            {
                return;
            }

            var oldPath = node.NodePath;
            node.AsRoot();
            var newPath = node.NodePath;

            this.Service<TNodePathRepairer>()
                .UpdateDescendantsNodePath<TNode>(oldPath, newPath);
        }

        private TNode LoadAggregate<TNode, TId>(TId? id)
            where TNode : TreeNode<TId>
            where TId : struct
        {
            return id != null ? this.Service<IRepository<TNode, TId>>().Load(id.Value) : null;
        }
    }
}
